#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <stdbool.h>
#include <pthread.h>
#include <semaphore.h>
#include <termios.h>

#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <linux/fb.h>
#include <linux/un.h>

#include <arpa/inet.h>
#include <netinet/in.h>

//头文件申明管道文件描述符
#include "head.h"

int fd_in;
int fd_out;
int fifo_in;
int fifo_out;



int init_tty(char *ttyname)
{
	int fd = open(ttyname, O_RDWR);

	struct termios cfg;
	bzero(&cfg, sizeof(cfg));

	cfmakeraw(&cfg);

	cfsetospeed(&cfg, B9600);
	cfsetispeed(&cfg, B9600);

	cfg.c_cflag &= ~CSTOPB;
	cfg.c_cflag |= (CREAD | CLOCAL);

	cfg.c_cc[VTIME] = 0;
	cfg.c_cc[VMIN]  = 1;

	tcflush(fd, TCIFLUSH);
	tcflush(fd, TCOFLUSH);

	if(tcsetattr(fd, TCSANOW, &cfg) != 0)
	{
		perror("初始化串口失败");
		exit(0);
	}

	return fd;
}

void BCC(uint8_t req[])
{
	int pos = req[0]-2;

	uint8_t bcc = 0;
	int i=0;
	for(i; i<pos; i++)
	{
		bcc ^= req[i];
	}
	req[pos] = ~bcc;
}

bool request_card(int fd)
{
	char req[7]; // 一帧
	bzero(req, 7);

	req[0] = 0x07; // 帧总长度
	req[1] = 0x02; // 指定命令的类型为: ISO14443A
	req[2] = 'A';  // 命令: 探测是否有卡片在附近
	req[3] = 1;    // 命令的参数的长度
	req[4] = 0x26; // 命令的参数: 0x26 IDLE 0x52 ALL
	req[6] = 0x03; // 结束符
	BCC(req);

	// 发送探测指令
	write(fd, req, req[0]);

	usleep(10*1000);

	char ans[256];
	bzero(ans, 256);

	// 读取读卡器的应答
	read(fd, ans, 256);
	return ans[2] == 0x00;
}

uint32_t get_id(int fd)
{
	char req[8]; // 一帧
	bzero(req, 8);

	req[0] = 0x08; // 帧总长度
	req[1] = 0x02; // 指定命令的类型为: ISO14443A
	req[2] = 'B';  // 命令: 获取卡片的ID
	req[3] = 0x02; // 命令的参数的长度
	req[4] = 0x93; // 命令的参数: 防碰撞级别
	req[5] = 0x00; // 命令的参数: 序列号长度（0代表没有序列号）
	req[7] = 0x03; // 结束符
	BCC(req);

	// 发送指令
	write(fd, req, req[0]);

	usleep(10*1000);

	char ans[256];
	bzero(ans, 256);

	// 读取读卡器的应答
	read(fd, ans, 256);

	if(ans[2] != 0x00)
	{
		return -1;
	}

	uint32_t id = 0;

	// 读取卡号
	// memcpy(id, &ans[4], ans[3]);
	int i=ans[3]-1,j=0;
	for(i, j; i>=0; i--, j++)
	{
		memcpy((char *)&id+j, &ans[4+i], 1);
	}
	return id;
}

int flag = 1;
void f(int sig)
{
	flag = 1;
}

void usage(int argc, char **argv)
{
	if(argc != 3)
	{
		fprintf(stderr, "用法: %s <入库串口> <出库串口>\n", argv[0]);
		exit(0);
	}
}

void *routine(void *arg)
{
		
	//定义卡号
     uint32_t id; 
	//子线程负责入库
	while(1)
	{
	   
	   
		// 向读卡器发送监测指令
		if(!request_card(fd_in))
		{
			usleep(300*1000);
			fprintf(stderr, "等待车辆。。。\r");
			continue;
		}
		
		// 向读卡器发送索取ID指令
		id = get_id(fd_in);

		if(id == 0 || id == 0xFFFFFFFF)
		{
			continue;
		}
        
		if(flag)
		{
		    fprintf(stderr,"RFID:检测到入库卡号: %u\n", id);

            //写入入库管道
			write(fifo_in,&id,sizeof(id));
					
			flag = 0;
		}
		//alarm也称为闹钟函数,它可以在进程中设置一个定时器,
		//当定时器指定的时间到时,它向进程发送SIGALRM信号。
		alarm(1);
		
	}
	pthread_exit(NULL);
}
		                                       //入库串口     //出库串口 
int main(int argc, char **argv) // ./RFID_demo /dev/ttySACx /dev/ttySACy 
{
	
	usage(argc, argv);

	// 初始化出入库串口
    fd_in = init_tty(argv[1]);
	fd_out = init_tty(argv[2]);
   
    printf("tty....");
	
    //为SIGALRM信号设置相应函数
	signal(SIGALRM,f);
	

	// 打开管道
	fifo_in  = open(RFID_SQLite_in,  O_WRONLY);
    fifo_out = open(RFID_SQLite_out, O_WRONLY);
	//创建子线程负责入库
	pthread_t tid;
	pthread_create(&tid,NULL,routine,NULL);
	
	//定义卡号
     uint32_t id; 
	//主线程负责出库
	while(1)
	{
	      
		// 向读卡器发送监测指令
		if(!request_card(fd_out))
		{
			usleep(300*1000);
			fprintf(stderr, "等待车辆。。。\r");
			continue;
		}
		
		// 向读卡器发送索取ID指令
		id = get_id(fd_out);

		if(id == 0 || id == 0xFFFFFFFF)
		{
			continue;
		}
        
		if(flag)
		{
		    fprintf(stderr,"RFID:检测到出库卡号: %u\n", id);

            //写入出库管道
			write(fifo_out,&id,sizeof(id));
				
			flag = 0;
		}
		//alarm也称为闹钟函数,它可以在进程中设置一个定时器,
		//当定时器指定的时间到时,它向进程发送SIGALRM信号。
		alarm(1);
		
	}
    
	close(fd_in);
	close(fd_out);
	close(fifo_in);
	close(fifo_out);
	pthread_exit(NULL);
	return 0;
}
